package cn.net.cfss.fgbp.auth.controller;

import cn.net.cfss.fgbp.api.console.inte.ISysUserService;
import cn.net.cfss.fgbp.api.console.vo.SysUserLoginVo;
import cn.net.cfss.fgbp.auth.common.Constants;
import cn.net.cfss.fgbp.auth.service.AuthService;
import cn.net.cfss.fgbp.auth.util.FgbpUtil;
import cn.net.cfss.fgbp.auth.util.SliderCheckUtil;
import cn.net.cfss.fgbp.auth.vo.Captcha;
import cn.net.cfss.fgbp.auth.vo.LoginUserVo;
import cn.net.cfss.fgbp.base.common.GlobalConstants;
import cn.net.cfss.fgbp.base.constant.ErrCodeEnum;
import cn.net.cfss.fgbp.base.controller.BaseController;
import cn.net.cfss.fgbp.base.except.CodeException;
import cn.net.cfss.fgbp.base.util.ReturnUtil;
import cn.net.cfss.fgbp.base.util.StringUtils;
import cn.net.cfss.fgbp.base.util.UuidUtil;
import cn.net.cfss.fgbp.base.vo.BaseReqVo;
import cn.net.cfss.fgbp.base.vo.BaseRespVo;
import cn.net.cfss.fgbp.base.vo.ReturnVo;
import cn.net.cfss.fgbp.base.vo.UserVo;
import cn.net.cfss.fgbp.spi.manage.inte.IFscTenantUserService;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class AuthController extends BaseController {


    @Autowired
    private AuthService authService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private IFscTenantUserService fscTenantUserService;

    @Value("${captcha.image.filepath:/data/share/ycloud/auth/captcha.png}")
    private String imageFilePath;

    /**
     * 图形验证码有效期（单位：分钟）
     */
    @Value("${captcha.time.out:1}")
    private int captchaTimeOut;

    /**
     * 图形验证码校验是否开启
     */
    @Value("${enable.validate.captcha:true}")
    private boolean enableValidateCaptcha;

    @Value("${captcha.slid.distance}")
    private Integer slidDistance;


    /**
     * 验证码获取接口
     *
     * @throws IOException
     */
    @RequestMapping("/captcha")
    public String captcha() throws IOException {
        //随机生成cookie值
        String cookieValue = UuidUtil.getUUID();
        //将cookie值添加到response
        Cookie cookie = new Cookie(Constants.CAPTCHA_COOKIE_NAME, cookieValue);
        cookie.setPath("/");//设置cookie的根路径
        response.addCookie(cookie);
        //根据配置生成验证码对象
        Captcha build = SliderCheckUtil.build(imageFilePath);
        //缓存进redis的对象，只需要存x和y轴坐标
        Captcha chcheCaptcha = new Captcha();
        chcheCaptcha.setxAxis(build.getxAxis());
        chcheCaptcha.setyAxis(build.getyAxis());
        String json = JSONObject.toJSONString(chcheCaptcha);
        //将验证码的json存储到redis，并设置过期时间，单位（分钟），默认5分钟有效期;
        redisTemplate.opsForValue().set(cookieValue, json, captchaTimeOut, TimeUnit.MINUTES);
        log.info("cookie={}，验证码：{}", cookieValue, json);

        //返回验证码对象时，清空x轴位置
        build.setxAxis(null);
        return ReturnUtil.returnSucc(build);
    }

    @PostMapping("/auth")
    public ReturnVo login(@RequestBody BaseReqVo<LoginUserVo> paras, @CookieValue(required = false, name = Constants.CAPTCHA_COOKIE_NAME) String cookieValue){
        Map<String,Object> resultMap = new HashMap<>();
        String userName=paras.getPlain().getUserName();
        String password=paras.getPlain().getPassword();
        String xAxis = paras.getPlain().getxAxis();
        

        //如果开启了验证码校验
        //校验滑块验证码
        ErrCodeEnum errCodeEnum = checkslidCaptcha(xAxis, cookieValue);
        if (errCodeEnum != null) {
            return new ReturnVo(new BaseRespVo(errCodeEnum));
        }

        //账号密码校验
        String realIp = FgbpUtil.getRealIp(request);
        SysUserLoginVo sysUserLoginVo=sysUserService.login(userName,password, realIp);
        String token = authService.buildJWT(sysUserLoginVo.getUserId(),userName);
        authService.cacheRoles(sysUserLoginVo.getRoles(),sysUserLoginVo.getUserId());
        UserVo userVo=new UserVo();
        userVo.setUserName(sysUserLoginVo.getName());
        userVo.setLoginName(sysUserLoginVo.getUsername());
        userVo.setUserId(sysUserLoginVo.getUserId());
        userVo.setEmail(sysUserLoginVo.getEmail());
        userVo.setCellPhone(sysUserLoginVo.getCellPhone());
        userVo.setSpId(sysUserLoginVo.getServiceProvider());
        Long tenantId = fscTenantUserService.queryTenantIdByUserid(sysUserLoginVo.getUserId());
        userVo.setTenantId(tenantId);
        if(!CollectionUtils.isEmpty(sysUserLoginVo.getProjectIds()))
        {
            StringBuffer sb=new StringBuffer();
            for(String projectId:sysUserLoginVo.getProjectIds())
            {
                sb.append(projectId).append(",");
            }
            userVo.setProjectIds(sb.toString());
        }
        authService.cacheToken(token,userVo);
        response.addHeader(Constants.HEADER_AUTHORIZATION,token);
        response.addHeader("Access-Control-Expose-Headers",Constants.HEADER_AUTHORIZATION);
        //authService.saveToken(token,userName);
        //返回结果
        ReturnVo returnVo=new ReturnVo(new BaseRespVo(ErrCodeEnum.SUCC));
        return returnVo;
    }


    /**
     * 核对滑动验证码
     * @return
     */
    private ErrCodeEnum checkslidCaptcha(String xAxis, String cookieValue) {

        if (!enableValidateCaptcha) {
            log.info("滑动验证码已关闭");
            return null;
        }

        if (cn.net.cfss.fgbp.base.util.StringUtils.isEmpty(xAxis) || StringUtils.isEmpty(cookieValue)) {
            log.error("校验滑动验证码异常，xAxis:{}, cookieValue:{}", xAxis, cookieValue);
            return ErrCodeEnum.ERR_VAII;
        }

        String json = redisTemplate.opsForValue().get(cookieValue);
        Captcha captcha = JSONObject.parseObject(json, Captcha.class);
        if (captcha == null) {
            //缓存失效
            return ErrCodeEnum.ERR_CAPTCHA;
        }
        //校验验证码
        int xAxisInt = Integer.valueOf(xAxis);
        int dValue = xAxisInt - captcha.getxAxis();
        if (Math.abs(dValue) > slidDistance) {
            //两者差值超过配置值，验证码校验失败
            return ErrCodeEnum.ERR_CAPTCHA;
        }
        redisTemplate.delete(cookieValue);
        return null;
    }




}